package butines.game2.graph;

import java.awt.Color;
import java.awt.Graphics2D;

import butines.common.math.Vector2D;

public class GraphHelper {

    // --------------------------- ValidNeighbour -----------------------------
    //
    // returns true if x,y is a valid position in the map
    // ------------------------------------------------------------------------
    private static boolean isValidNeighbour(int x, int y, int NumCellsX, int NumCellsY) {
        return (x >= 0 && x < NumCellsX && y >= 0 && y < NumCellsY);
    }

    // ------------ GraphHelper_AddAllNeighboursToGridNode ------------------
    //
    // use to add he eight neighboring edges of a graph node that
    // is positioned in a grid layout
    // ------------------------------------------------------------------------
    public static void addAllNeighboursToGridNode(SparseGraph<NavGraphNode, NavGraphEdge> graph,
            int row, int col, int numCellsX, int numCellsY) {

        for (int i = -1; i < 2; i++) {
            for (int j = -1; j < 2; j++) {
               
                int nodeX = col + j;
                int nodeY = row + i;

                // skip if equal to this node
                if ((i == 0) && (j == 0)) {
                    continue;
                }

                // check to see if this is a valid neighbour
                if (!isValidNeighbour(nodeX, nodeY, numCellsX, numCellsY)) {
                    continue;
                }

                // calculate the distance to this node
                int from = row * numCellsX + col;
                int to =  nodeY * numCellsX + nodeX;
                
                Vector2D posNode = graph.getNode(from).getPosition();
                Vector2D posNeighbour = graph.getNode(to).getPosition();

                float dist = posNode.distance(posNeighbour);

                // this neighbour is okay so it can be added
                NavGraphEdge newEdge = new NavGraphEdge(from, to, dist);
                graph.addEdge(newEdge);
                
            }
        }
    }

    // --------------------------- GraphHelper_CreateGrid --------------------------
    //
    // creates a graph based on a grid layout. This function requires the
    // dimensions of the environment and the number of cells required horizontally
    // and vertically
    // -----------------------------------------------------------------------------
    public static void createGrid(SparseGraph<NavGraphNode, NavGraphEdge> graph,
            int width, int height, int numCellsX, int numCellsY) {
        
        NavGraphNode[][] grid = new NavGraphNode[numCellsY][numCellsX];
        
        // need some temporaries to help calculate each node center
        float cellWidth = (float) width / (float) numCellsX;
        float cellHeight = (float) height / (float) numCellsY;

        float midX = cellWidth / 2;
        float midY = cellHeight / 2;

        // first create all the nodes
        for (int row = 0; row < numCellsY; row++) {
            for (int col = 0; col < numCellsX; col++) {
                int index = graph.getNextFreeNodeIndex();
                Vector2D position = new Vector2D(midX + (col * cellWidth), midY + (row * cellHeight));
                NavGraphNode node = new NavGraphNode(index, position);
                node.setGrid(grid);
                node.setRow(row);
                node.setCol(col);
                graph.addNode(node);
                grid[row][col] = node;
            }
        }
        // now to calculate the edges. (A position in a 2d array [x][y] is the
        // same as [y*NumCellsX + x] in a 1d array). Each cell has up to eight
        // neighbours.
        for (int row = 0; row < numCellsY; ++row) {
            for (int col = 0; col < numCellsX; ++col) {
                addAllNeighboursToGridNode(graph, row, col, numCellsX, numCellsY);
            }
        }
        
    }

    public static void render(Graphics2D g2d,
            SparseGraph<NavGraphNode, NavGraphEdge> graph,
            Color color, boolean drawNodeIDs) {

        // just return if the graph has no nodes
        if (graph.getNumNodes() == 0) {
            return;
        }

        g2d.setColor(color);

        for (NavGraphNode node : graph.getNodes()) {
            int x = Math.round(node.getPosition().x) - 3;
            int y = Math.round(node.getPosition().y) - 3;
            g2d.fillOval(x, y, 5, 5);
            if (drawNodeIDs) {
                g2d.setColor(new Color(200, 200, 200));
                g2d.drawString(String.valueOf(node.getIndex()), (int) node.getPosition().x - 12, (int) node.getPosition().y - 3);
            }
            if (node.getIndex() == -1) {
                continue;
            }
            for (NavGraphEdge edge : graph.getEdges(node.getIndex())) {
                NavGraphNode to = graph.getNode(edge.getTo());
                g2d.drawLine((int) node.getPosition().x, (int) node.getPosition().y, (int) to.getPosition().x, (int) to.getPosition().y);
            }
        }

    }
    
}
